#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
WitTkChart - 基于tkinter Canvas的图表可视化库

该库允许用户通过简单的API调用，创建和更新多种类型的图表，包括柱状图、折线图、饼图等。
配色方案参考了Echarts图表库的设计。

作者: Wiktok
邮箱: forwt@qq.com，1346363063@qq.com
版本: 1.0.0
日期: 2025-09-24
"""

import tkinter as tk
from tkinter import ttk
import math
from typing import List, Dict, Tuple, Union, Optional
import random

# 定义Echarts风格的配色方案
ECHARTS_COLORS = [
    '#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', 
    '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc', '#5470c6',
    '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272'
]

class WitTkChart:
    """
    WitTkChart主类，用于创建和管理基于tkinter Canvas的图表
    
    属性:
        root: tk.Tk - tkinter根窗口
        canvas: tk.Canvas - 用于绘制图表的Canvas对象
        chart_type: str - 图表类型
        data: List[Union[int, float]] - 图表数据
        categories: List[str] - 数据分类标签
        width: int - 图表宽度
        height: int - 图表高度
        margin: Dict[str, int] - 图表边距
        colors: List[str] - 图表颜色列表
        title: str - 图表标题
        is_dynamic: bool - 是否支持动态更新
    """
    
    def __init__(self, root: Optional[tk.Tk] = None, width: int = 800, height: int = 600, 
                 chart_type: str = 'bar', data: Optional[List[Union[int, float]]] = None, 
                 categories: Optional[List[str]] = None, title: str = '图表标题'):
        """
        初始化WitTkChart对象
        
        参数:
            root: tk.Tk - tkinter根窗口，默认为None，此时会创建一个新窗口
            width: int - 图表宽度，默认为800
            height: int - 图表高度，默认为600
            chart_type: str - 图表类型，默认为'bar'
            data: List[Union[int, float]] - 图表数据，默认为None
            categories: List[str] - 数据分类标签，默认为None
            title: str - 图表标题，默认为'图表标题'
        """
        self.root = root or tk.Tk()
        # 只有当root是Tk对象时才设置标题
        if isinstance(self.root, tk.Tk):
            self.root.title(title)
        
        # 设置图表尺寸和边距
        self.width = width
        self.height = height
        self.margin = {
            'top': 60,    # 顶部边距，留出标题空间
            'right': 40,  # 右侧边距
            'bottom': 60, # 底部边距，留出x轴标签空间
            'left': 60    # 左侧边距，留出y轴标签空间
        }
        
        # 创建Canvas对象
        self.canvas = tk.Canvas(
            self.root, 
            width=self.width, 
            height=self.height, 
            bg='white', 
            highlightthickness=0
        )
        self.canvas.pack(fill=tk.BOTH, expand=True)
        
        # 初始化图表数据和配置
        self.chart_type = chart_type
        self.data = data or []
        self.categories = categories or []
        self.colors = ECHARTS_COLORS
        self.title = title
        self.is_dynamic = False
        
        # 加载动画相关属性
        self.is_loading = False
        self.loading_progress = 0
        self.loading_animation_id = None
        
        # 绑定窗口调整事件
        self.root.bind('<Configure>', self._on_resize)
        
        # 使用after_idle确保UI初始化完成后再绘制图表
        self.root.after_idle(self._start_initial_rendering)
    
    def _on_resize(self, event: tk.Event) -> None:
        """
        处理窗口大小调整事件
        
        参数:
            event: tk.Event - 窗口调整事件对象
        """
        # 获取新的窗口尺寸
        new_width = event.width
        new_height = event.height
        
        # 更新Canvas尺寸
        self.canvas.config(width=new_width, height=new_height)
        
        # 重绘图表
        self.width = new_width
        self.height = new_height
        self.draw_chart()
    
    def set_data(self, data: List[Union[int, float]], categories: Optional[List[str]] = None) -> None:
        """
        设置图表数据
        
        参数:
            data: List[Union[int, float]] - 新的图表数据
            categories: List[str] - 新的数据分类标签，默认为None
        """
        self.data = data
        if categories is not None:
            self.categories = categories
        self.draw_chart()
    
    def set_chart_type(self, chart_type: str) -> None:
        """
        设置图表类型
        
        参数:
            chart_type: str - 新的图表类型
        """
        self.chart_type = chart_type
        self.draw_chart()
    
    def set_title(self, title: str) -> None:
        """
        设置图表标题
        
        参数:
            title: str - 新的图表标题
        """
        self.title = title
        # 只有当root是Tk对象时才设置标题
        if isinstance(self.root, tk.Tk):
            self.root.title(title)
        self.draw_chart()
    
    def _start_initial_rendering(self) -> None:
        """
        启动初始渲染过程，显示加载动画
        """
        # 标记为加载状态
        self.is_loading = True
        self.loading_progress = 0
        
        # 先绘制标题
        self.canvas.delete('all')
        self._draw_title()
        
        # 开始加载动画
        self._update_loading_animation()
    
    def _update_loading_animation(self) -> None:
        """
        更新加载动画
        """
        if not self.is_loading:
            return
        
        # 增加加载进度
        self.loading_progress += 2
        
        # 绘制加载动画
        self._draw_loading_animation()
        
        # 检查是否加载完成
        if self.loading_progress >= 100:
            # 完成加载，绘制实际图表
            self.is_loading = False
            self.draw_chart()
        else:
            # 继续加载动画
            self.loading_animation_id = self.root.after(30, self._update_loading_animation)
    
    def _draw_loading_animation(self) -> None:
        """
        绘制加载动画
        """
        # 清空Canvas但保留标题
        self.canvas.delete('loading', 'loading_text')
        
        # 计算图表中心
        center_x = self.width // 2
        center_y = (self.height - self.margin['top']) // 2 + self.margin['top']
        radius = min(center_x - self.margin['left'], center_y - self.margin['top'], 
                    self.width - center_x - self.margin['right'], self.height - center_y - self.margin['bottom']) * 0.4
        
        # 绘制加载圆环背景
        self.canvas.create_oval(
            center_x - radius, center_y - radius, 
            center_x + radius, center_y + radius,
            fill='', outline='#f0f0f0', width=10,
            tags='loading'
        )
        
        # 绘制加载进度圆弧
        arc_angle = self.loading_progress * 3.6  # 0-360度
        self.canvas.create_arc(
            center_x - radius, center_y - radius, 
            center_x + radius, center_y + radius,
            start=90, extent=-arc_angle,  # 从顶部开始逆时针绘制
            fill='', outline=self.colors[0], width=10,
            tags='loading'
        )
        
        # 绘制加载进度文本
        self.canvas.create_text(
            center_x, center_y, 
            text=f'加载中 {self.loading_progress}%', 
            font=('SimHei', 14, 'bold'),
            fill='#333333',
            tags='loading_text'
        )
    
    def draw_chart(self) -> None:
        """
        根据当前配置绘制图表
        """
        # 清空Canvas
        self.canvas.delete('all')
        
        # 绘制标题
        self._draw_title()
        
        # 根据图表类型调用相应的绘制方法
        if not self.data:
            # 显示空数据提示
            self._draw_empty_data_message()
            return
        
        # 使用动画效果绘制图表（根据图表类型选择合适的动画方法）
        if self.chart_type == 'bar':
            self._draw_bar_chart_with_animation()
        elif self.chart_type == 'line':
            self._draw_line_chart_with_animation()
        elif self.chart_type == 'pie':
            self._draw_pie_chart_with_animation()
        elif self.chart_type == 'scatter':
            self._draw_scatter_chart_with_animation()
        elif self.chart_type == 'radar':
            self._draw_radar_chart_with_animation()
        elif self.chart_type == 'tree':
            self._draw_tree_chart_with_animation()
        elif self.chart_type == 'sunburst':
            self._draw_sunburst_chart_with_animation()
        elif self.chart_type == 'boxplot':
            self._draw_boxplot_chart_with_animation()
        elif self.chart_type == 'heatmap':
            self._draw_heatmap_chart_with_animation()
        elif self.chart_type == 'map':
            self._draw_map_chart_with_animation()
        elif self.chart_type == 'sankey':
            self._draw_sankey_chart_with_animation()
        elif self.chart_type == 'funnel':
            self._draw_funnel_chart_with_animation()
        elif self.chart_type == 'gauge':
            self._draw_gauge_chart_with_animation()
        else:
            # 显示不支持的图表类型提示
            self._draw_unsupported_chart_type_message()
    
    def _draw_title(self) -> None:
        """
        绘制图表标题
        """
        self.canvas.create_text(
            self.width // 2, 
            self.margin['top'] // 2, 
            text=self.title, 
            font=('SimHei', 16, 'bold'),
            fill='#333333'
        )
    
    def _draw_empty_data_message(self) -> None:
        """
        绘制空数据提示信息
        """
        self.canvas.create_text(
            self.width // 2, 
            self.height // 2, 
            text='暂无数据', 
            font=('SimHei', 14),
            fill='#999999'
        )
    
    def _draw_unsupported_chart_type_message(self) -> None:
        """
        绘制不支持的图表类型提示信息
        """
        self.canvas.create_text(
            self.width // 2, 
            self.height // 2, 
            text=f'不支持的图表类型: {self.chart_type}', 
            font=('SimHei', 14),
            fill='#ff0000'
        )
    
    def _draw_bar_chart(self) -> None:
        """
        绘制柱状图
        """
        # 直接调用带动画的版本
        self._draw_bar_chart_with_animation()
        
    def _draw_bar_chart_with_animation(self) -> None:
        """
        绘制带加载动画的柱状图
        """
        # 计算可用绘图区域
        plot_width = self.width - self.margin['left'] - self.margin['right']
        plot_height = self.height - self.margin['top'] - self.margin['bottom']
        
        if not self.data:
            self._draw_empty_data_message()
            return
        
        # 确定数据范围
        max_value = max(self.data) if self.data else 1
        
        # 计算柱子宽度和间距
        bar_count = len(self.data)
        bar_width = plot_width / bar_count * 0.6
        bar_space = plot_width / bar_count * 0.4
        
        # 绘制坐标轴
        self.canvas.create_line(
            self.margin['left'], self.margin['top'], 
            self.margin['left'], self.height - self.margin['bottom'],
            width=2
        )
        self.canvas.create_line(
            self.margin['left'], self.height - self.margin['bottom'], 
            self.width - self.margin['right'], self.height - self.margin['bottom'],
            width=2
        )
        
        # 绘制Y轴刻度
        y_ticks = 5
        for i in range(y_ticks + 1):
            y = self.height - self.margin['bottom'] - (plot_height / y_ticks) * i
            self.canvas.create_line(
                self.margin['left'] - 5, y, 
                self.margin['left'], y,
                width=1
            )
            self.canvas.create_text(
                self.margin['left'] - 10, y, 
                text=f'{int(max_value * i / y_ticks)}', 
                font=('SimHei', 10),
                anchor='e'
            )
        
        # 初始化动画参数
        self.bar_animation_progress = 0
        self.bar_animation_data = self.data
        self.bar_animation_max_value = max_value
        self.bar_animation_plot_height = plot_height
        self.bar_animation_bar_width = bar_width
        self.bar_animation_bar_space = bar_space
        self.bar_animation_categories = self.categories
        
        # 开始动画
        self._update_bar_animation()
        
    def _update_bar_animation(self) -> None:
        """
        更新柱状图动画
        """
        # 增加动画进度
        self.bar_animation_progress += 0.05
        if self.bar_animation_progress > 1:
            self.bar_animation_progress = 1
        
        # 清空之前的绘制内容（保留坐标轴等）
        self.canvas.delete('bar')
        
        max_value = self.bar_animation_max_value
        plot_height = self.bar_animation_plot_height
        bar_width = self.bar_animation_bar_width
        bar_space = self.bar_animation_bar_space
        data = self.bar_animation_data
        categories = self.bar_animation_categories
        
        # 绘制柱状图（带动画）
        for i, value in enumerate(data):
            # 计算当前显示的值（根据动画进度）
            current_value = value * self.bar_animation_progress
            
            # 计算柱子的位置
            x = self.margin['left'] + bar_space / 2 + (bar_width + bar_space) * i
            y = self.height - self.margin['bottom'] - (current_value / max_value) * plot_height
            
            # 使用Echarts配色
            color = self.colors[i % len(self.colors)]
            
            # 绘制柱子（使用进度控制高度）
            self.canvas.create_rectangle(
                x, y, 
                x + bar_width, self.height - self.margin['bottom'],
                fill=color, outline='',
                tags='bar'
            )
            
            # 当动画进度接近完成时绘制数值标签
            if self.bar_animation_progress > 0.8:
                # 数值标签随进度变化
                self.canvas.create_text(
                    x + bar_width / 2, y - 10, 
                    text=str(int(current_value)), 
                    font=('SimHei', 10),
                    fill='#333333',
                    tags='bar'
                )
            
        # 绘制X轴标签（随动画进度显示）
        if self.bar_animation_progress > 0.9 and categories:
            for i, category in enumerate(categories):
                if i < len(data):
                    x = self.margin['left'] + bar_space / 2 + (bar_width + bar_space) * i + bar_width / 2
                    self.canvas.create_text(
                        x, self.height - self.margin['bottom'] + 20, 
                        text=category, 
                        font=('SimHei', 10),
                        anchor='n',
                        angle=45,
                        tags='bar'
                    )
        
        # 继续动画或结束
        if self.bar_animation_progress < 1:
            self.root.after(30, self._update_bar_animation)
    
    def _draw_line_chart(self) -> None:
        """
        绘制折线图
        """
        # 直接调用带动画的版本
        self._draw_line_chart_with_animation()
        
    def _draw_line_chart_with_animation(self) -> None:
        """
        绘制带加载动画的折线图
        """
        # 计算可用绘图区域
        plot_width = self.width - self.margin['left'] - self.margin['right']
        plot_height = self.height - self.margin['top'] - self.margin['bottom']
        
        # 确定数据范围
        try:
            # 尝试将数据转换为数值并找到最大值
            numeric_data = []
            for item in self.data:
                try:
                    numeric_data.append(float(item))
                except (ValueError, TypeError):
                    numeric_data.append(0)  # 无法转换的使用0
            max_value = max(numeric_data) if numeric_data else 1
        except (ValueError, TypeError):
            max_value = 1  # 出错时使用默认值
        
        # 计算点的位置
        point_count = len(self.data)
        if point_count < 2:
            # 数据点太少，无法绘制折线图
            self._draw_empty_data_message()
            return
        
        # 绘制坐标轴
        self.canvas.create_line(
            self.margin['left'], self.margin['top'], 
            self.margin['left'], self.height - self.margin['bottom'],
            width=2
        )
        self.canvas.create_line(
            self.margin['left'], self.height - self.margin['bottom'], 
            self.width - self.margin['right'], self.height - self.margin['bottom'],
            width=2
        )
        
        # 绘制Y轴刻度
        y_ticks = 5
        for i in range(y_ticks + 1):
            y = self.height - self.margin['bottom'] - (plot_height / y_ticks) * i
            self.canvas.create_line(
                self.margin['left'] - 5, y, 
                self.margin['left'], y,
                width=1
            )
            self.canvas.create_text(
                self.margin['left'] - 10, y, 
                text=f'{int(max_value * i / y_ticks)}', 
                font=('SimHei', 10),
                anchor='e'
            )
        
        # 初始化动画参数
        self.line_animation_progress = 0
        self.line_animation_data = self.data
        self.line_animation_max_value = max_value
        self.line_animation_plot_height = plot_height
        self.line_animation_plot_width = plot_width
        self.line_animation_point_count = point_count
        self.line_animation_categories = self.categories
        self.line_animation_numeric_data = numeric_data
        
        # 开始动画
        self._update_line_animation()
        
    def _update_line_animation(self) -> None:
        """
        更新折线图动画
        """
        # 增加动画进度
        self.line_animation_progress += 0.05
        if self.line_animation_progress > 1:
            self.line_animation_progress = 1
        
        # 清空之前的绘制内容（保留坐标轴等）
        self.canvas.delete('line')
        
        max_value = self.line_animation_max_value
        plot_height = self.line_animation_plot_height
        plot_width = self.line_animation_plot_width
        point_count = self.line_animation_point_count
        data = self.line_animation_data
        categories = self.line_animation_categories
        numeric_data = self.line_animation_numeric_data
        
        # 计算当前显示的数据点
        visible_points = int(point_count * self.line_animation_progress)
        if visible_points < 1:
            visible_points = 1
        
        # 绘制折线（带动画）
        points = []
        for i in range(visible_points):
            # 计算当前点的动画值
            current_value = numeric_data[i] * self.line_animation_progress
            
            # 计算点的位置
            x = self.margin['left'] + (plot_width / (point_count - 1)) * i
            y = self.height - self.margin['bottom'] - (current_value / max_value) * plot_height
            points.append((x, y))
            
            # 绘制数据点（随动画进度放大）
            dot_size = 4 * self.line_animation_progress
            self.canvas.create_oval(
                x - dot_size, y - dot_size, 
                x + dot_size, y + dot_size,
                fill=self.colors[0], outline='',
                tags='line'
            )
            
            # 当动画进度接近完成时显示数值
            if self.line_animation_progress > 0.8:
                self.canvas.create_text(
                    x, y - 10, 
                    text=str(int(current_value)), 
                    font=('SimHei', 10),
                    fill='#333333',
                    tags='line'
                )
        
        # 绘制连接线
        if len(points) > 1:
            self.canvas.create_line(
                points, 
                width=2 * self.line_animation_progress, 
                fill=self.colors[0],
                tags='line'
            )
        
        # 绘制X轴标签（随动画进度显示）
        if self.line_animation_progress > 0.9 and categories:
            for i, category in enumerate(categories):
                if i < point_count:
                    x = self.margin['left'] + (plot_width / (point_count - 1)) * i
                    self.canvas.create_text(
                        x, self.height - self.margin['bottom'] + 20, 
                        text=category, 
                        font=('SimHei', 10),
                        anchor='n',
                        angle=45,
                        tags='line'
                    )
        
        # 继续动画或结束
        if self.line_animation_progress < 1:
            self.root.after(30, self._update_line_animation)
    
    def _draw_pie_chart(self) -> None:
        """
        绘制饼图
        """
        # 直接调用带动画的版本
        self._draw_pie_chart_with_animation()
        
    def _draw_pie_chart_with_animation(self) -> None:
        """
        绘制带加载动画的饼图
        """
        # 计算图表中心和半径
        center_x = self.width // 2
        center_y = (self.height - self.margin['top']) // 2 + self.margin['top']
        radius = min(center_x - self.margin['left'], center_y - self.margin['top'], 
                    self.width - center_x - self.margin['right'], self.height - center_y - self.margin['bottom']) * 0.8
        
        # 计算总数据和每个数据的角度
        # 处理可能包含元组的数据
        try:
            # 尝试直接求和
            total = sum(self.data)
        except TypeError:
            # 如果数据包含元组，尝试取出第一个元素
            try:
                total = sum(item[0] if isinstance(item, tuple) else item for item in self.data)
            except:
                # 如果仍然失败，使用默认值
                total = 0
        if total == 0:
            self._draw_empty_data_message()
            return
        
        # 初始化动画参数
        self.pie_animation_progress = 0
        self.pie_animation_data = self.data
        self.pie_animation_total = total
        self.pie_animation_center = (center_x, center_y)
        self.pie_animation_radius = radius
        self.pie_animation_categories = self.categories
        
        # 开始动画
        self._update_pie_animation()
        
    def _update_pie_animation(self) -> None:
        """
        更新饼图动画
        """
        # 增加动画进度
        self.pie_animation_progress += 0.05
        if self.pie_animation_progress > 1:
            self.pie_animation_progress = 1
        
        # 清空之前的绘制内容
        self.canvas.delete('pie')
        
        center_x, center_y = self.pie_animation_center
        radius = self.pie_animation_radius
        total = self.pie_animation_total
        data = self.pie_animation_data
        categories = self.pie_animation_categories
        
        # 计算当前动画覆盖的角度
        total_animation_angle = 360 * self.pie_animation_progress
        current_angle = 90  # 从顶部开始
        angle_remaining = total_animation_angle
        
        # 绘制饼图（带动画）
        for i, value in enumerate(data):
            # 计算当前扇形的实际角度
            sector_angle = 360 * value / total
            
            # 确定当前动画中显示的扇形角度
            if angle_remaining > 0:
                display_angle = min(sector_angle, angle_remaining)
                angle_remaining -= display_angle
            else:
                display_angle = 0
            
            if display_angle > 0:
                # 使用Echarts配色
                color = self.colors[i % len(self.colors)]
                
                # 绘制扇形（带动画）
                self.canvas.create_arc(
                    center_x - radius * self.pie_animation_progress, 
                    center_y - radius * self.pie_animation_progress, 
                    center_x + radius * self.pie_animation_progress, 
                    center_y + radius * self.pie_animation_progress,
                    start=current_angle, 
                    extent=display_angle, 
                    fill=color, 
                    outline='white', 
                    width=2,
                    tags='pie'
                )
                
                # 当动画进度接近完成时绘制数值标签
                if self.pie_animation_progress > 0.8:
                    # 计算扇形中心角度
                    label_angle = current_angle - display_angle / 2
                    mid_angle = math.radians(label_angle)
                    
                    # 计算标签位置
                    label_radius = radius * 1.2 * self.pie_animation_progress
                    label_x = center_x + math.cos(mid_angle) * label_radius
                    label_y = center_y - math.sin(mid_angle) * label_radius
                    
                    # 绘制标签
                    if categories and i < len(categories):
                        percentage = value / total * 100 if total > 0 else 0
                        label_text = f'{categories[i]}: {value} ({percentage:.1f}%)'
                        self.canvas.create_text(
                            label_x, label_y, 
                            text=label_text, 
                            font=('SimHei', 10),
                            fill='#333333',
                            anchor='center',
                            tags='pie'
                        )
            
            # 更新起始角度
            current_angle -= sector_angle
        
        # 继续动画或结束
        if self.pie_animation_progress < 1:
            self.root.after(30, self._update_pie_animation)
    
    def _draw_scatter_chart(self) -> None:
        """
        绘制散点图
        """
        # 直接调用带动画的版本
        self._draw_scatter_chart_with_animation()
        
    def _draw_scatter_chart_with_animation(self) -> None:
        """
        绘制带加载动画的散点图
        """
        # 计算可用绘图区域
        plot_width = self.width - self.margin['left'] - self.margin['right']
        plot_height = self.height - self.margin['top'] - self.margin['bottom']
        
        # 确定数据范围
        if len(self.data) < 2:
            self._draw_empty_data_message()
            return
        
        # 假设数据是二维的[(x1,y1), (x2,y2), ...]
        if isinstance(self.data[0], tuple) and len(self.data[0]) >= 2:
            x_data = [d[0] for d in self.data]
            y_data = [d[1] for d in self.data]
        else:
            # 如果数据是一维的，使用索引作为x值
            x_data = list(range(len(self.data)))
            y_data = self.data
        
        min_x, max_x = min(x_data), max(x_data)
        min_y, max_y = min(y_data), max(y_data)
        
        # 处理最大值和最小值相等的情况
        if max_x == min_x:
            max_x = min_x + 1
        if max_y == min_y:
            max_y = min_y + 1
        
        # 绘制坐标轴
        self.canvas.create_line(
            self.margin['left'], self.margin['top'], 
            self.margin['left'], self.height - self.margin['bottom'],
            width=2
        )
        self.canvas.create_line(
            self.margin['left'], self.height - self.margin['bottom'], 
            self.width - self.margin['right'], self.height - self.margin['bottom'],
            width=2
        )
        
        # 绘制刻度
        # X轴刻度
        x_ticks = 5
        for i in range(x_ticks + 1):
            x = self.margin['left'] + (plot_width / x_ticks) * i
            self.canvas.create_line(
                x, self.height - self.margin['bottom'], 
                x, self.height - self.margin['bottom'] + 5,
                width=1
            )
            self.canvas.create_text(
                x, self.height - self.margin['bottom'] + 15, 
                text=f'{min_x + (max_x - min_x) * i / x_ticks:.1f}', 
                font=('SimHei', 10),
                anchor='n'
            )
        
        # Y轴刻度
        y_ticks = 5
        for i in range(y_ticks + 1):
            y = self.height - self.margin['bottom'] - (plot_height / y_ticks) * i
            self.canvas.create_line(
                self.margin['left'] - 5, y, 
                self.margin['left'], y,
                width=1
            )
            self.canvas.create_text(
                self.margin['left'] - 10, y, 
                text=f'{min_y + (max_y - min_y) * i / y_ticks:.1f}', 
                font=('SimHei', 10),
                anchor='e'
            )
        
        # 初始化动画参数
        self.scatter_animation_progress = 0
        self.scatter_animation_x_data = x_data
        self.scatter_animation_y_data = y_data
        self.scatter_animation_min_x = min_x
        self.scatter_animation_max_x = max_x
        self.scatter_animation_min_y = min_y
        self.scatter_animation_max_y = max_y
        self.scatter_animation_plot_width = plot_width
        self.scatter_animation_plot_height = plot_height
        
        # 开始动画
        self._update_scatter_animation()
        
    def _update_scatter_animation(self) -> None:
        """
        更新散点图动画
        """
        # 增加动画进度
        self.scatter_animation_progress += 0.05
        if self.scatter_animation_progress > 1:
            self.scatter_animation_progress = 1
        
        # 清空之前的绘制内容
        self.canvas.delete('scatter')
        
        x_data = self.scatter_animation_x_data
        y_data = self.scatter_animation_y_data
        min_x = self.scatter_animation_min_x
        max_x = self.scatter_animation_max_x
        min_y = self.scatter_animation_min_y
        max_y = self.scatter_animation_max_y
        plot_width = self.scatter_animation_plot_width
        plot_height = self.scatter_animation_plot_height
        
        # 计算当前显示的数据点数量
        visible_points = int(len(x_data) * self.scatter_animation_progress)
        if visible_points < 1:
            visible_points = 1
        
        # 绘制散点（带动画）
        for i in range(visible_points):
            x_val, y_val = x_data[i], y_data[i]
            
            # 映射数据到Canvas坐标
            x = self.margin['left'] + (x_val - min_x) / (max_x - min_x) * plot_width
            y = self.height - self.margin['bottom'] - (y_val - min_y) / (max_y - min_y) * plot_height
            
            # 使用Echarts配色
            color = self.colors[i % len(self.colors)]
            
            # 绘制散点（随动画进度放大）
            dot_size = 5 * self.scatter_animation_progress
            self.canvas.create_oval(
                x - dot_size, y - dot_size, 
                x + dot_size, y + dot_size,
                fill=color, outline='',
                tags='scatter'
            )
        
        # 继续动画或结束
        if self.scatter_animation_progress < 1:
            self.root.after(30, self._update_scatter_animation)
    
    def _draw_radar_chart(self) -> None:
        """
        绘制雷达图
        """
        # 直接调用带动画的版本
        self._draw_radar_chart_with_animation()
        
    def _draw_radar_chart_with_animation(self) -> None:
        """
        绘制带加载动画的雷达图
        """
        # 计算图表中心和半径
        center_x = self.width // 2
        center_y = (self.height - self.margin['top']) // 2 + self.margin['top']
        radius = min(center_x - self.margin['left'], center_y - self.margin['top'], 
                    self.width - center_x - self.margin['right'], self.height - center_y - self.margin['bottom']) * 0.8
        
        # 检查数据和分类
        if not self.data or not self.categories:
            self._draw_empty_data_message()
            return
        
        # 确定数据范围
        try:
            # 尝试将数据转换为数值并找到最大值
            numeric_data = []
            for item in self.data:
                try:
                    numeric_data.append(float(item))
                except (ValueError, TypeError):
                    numeric_data.append(0)  # 无法转换的使用0
            max_value = max(numeric_data) if numeric_data else 1
            if max_value == 0:
                max_value = 1
        except (ValueError, TypeError):
            max_value = 1  # 出错时使用默认值
        
        # 计算角度间隔
        angle_step = 2 * math.pi / len(self.categories)
        
        # 绘制网格线
        levels = 5
        for level in range(1, levels + 1):
            level_radius = radius * level / levels
            points = []
            for i in range(len(self.categories)):
                angle = -math.pi / 2 + i * angle_step  # 从顶部开始
                x = center_x + level_radius * math.cos(angle)
                y = center_y + level_radius * math.sin(angle)
                points.append((x, y))
            self.canvas.create_polygon(points, outline='#dddddd', fill='', width=1)
        
        # 初始化动画参数
        self.radar_animation_progress = 0
        self.radar_animation_data = self.data
        self.radar_animation_categories = self.categories
        self.radar_animation_max_value = max_value
        self.radar_animation_center = (center_x, center_y)
        self.radar_animation_radius = radius
        self.radar_animation_angle_step = angle_step
        self.radar_animation_numeric_data = numeric_data
        
        # 开始动画
        self._update_radar_animation()
        
    def _update_radar_animation(self) -> None:
        """
        更新雷达图动画
        """
        # 增加动画进度
        self.radar_animation_progress += 0.05
        if self.radar_animation_progress > 1:
            self.radar_animation_progress = 1
        
        # 清空之前的绘制内容
        self.canvas.delete('radar')
        
        data = self.radar_animation_data
        categories = self.radar_animation_categories
        max_value = self.radar_animation_max_value
        center_x, center_y = self.radar_animation_center
        radius = self.radar_animation_radius
        angle_step = self.radar_animation_angle_step
        numeric_data = self.radar_animation_numeric_data
        
        # 绘制轴线和标签（随动画进度显示）
        if self.radar_animation_progress > 0.1:
            visible_axes = int(len(categories) * self.radar_animation_progress)
            if visible_axes < 1:
                visible_axes = 1
            
            for i in range(visible_axes):
                angle = -math.pi / 2 + i * angle_step  # 从顶部开始
                x = center_x + radius * math.cos(angle)
                y = center_y + radius * math.sin(angle)
                
                # 绘制轴线
                self.canvas.create_line(
                    center_x, center_y, 
                    x, y,
                    width=1, fill='#999999',
                    tags='radar'
                )
                
                # 当动画进度接近完成时绘制标签
                if self.radar_animation_progress > 0.8:
                    # 绘制标签
                    label_radius = radius * 1.1  # 标签位置半径
                    label_x = center_x + label_radius * math.cos(angle)
                    label_y = center_y + label_radius * math.sin(angle)
                    self.canvas.create_text(
                        label_x, label_y, 
                        text=categories[i], 
                        font=('SimHei', 10),
                        fill='#333333',
                        anchor='center',
                        tags='radar'
                    )
        
        # 绘制数据多边形和点
        data_points = []
        for i, value in enumerate(data):
            # 仅绘制当前进度可见的点
            if i < int(len(data) * self.radar_animation_progress):
                angle = -math.pi / 2 + i * angle_step  # 从顶部开始
                try:
                    # 确保value是数值类型
                    num_value = float(value) * self.radar_animation_progress
                    data_radius = radius * num_value / max_value
                except (ValueError, TypeError):
                    data_radius = 0  # 无法转换为数字时使用0
                x = center_x + data_radius * math.cos(angle)
                y = center_y + data_radius * math.sin(angle)
                data_points.append((x, y))
                
                # 绘制数据点（随动画进度放大）
                dot_size = 4 * self.radar_animation_progress
                self.canvas.create_oval(
                    x - dot_size, y - dot_size, 
                    x + dot_size, y + dot_size,
                    fill=self.colors[0], outline='',
                    tags='radar'
                )
        
        # 绘制多边形（随动画进度显示）
        if data_points and len(data_points) > 2:
            # 添加透明度效果
            self.canvas.create_polygon(
                data_points, 
                outline=self.colors[0], 
                fill=self.colors[0],  # 使用纯色填充
                width=2 * self.radar_animation_progress,
                tags='radar'
            )
        
        # 继续动画或结束
        if self.radar_animation_progress < 1:
            self.root.after(30, self._update_radar_animation)
    
    def _draw_tree_chart(self) -> None:
        """
        绘制树型图（简化版，实际应用中需要更复杂的层级数据结构）
        """
        # 直接调用带动画的版本
        self._draw_tree_chart_with_animation()
        
    def _draw_tree_chart_with_animation(self) -> None:
        """
        绘制带加载动画的树型图
        """
        # 计算可用绘图区域
        plot_width = self.width - self.margin['left'] - self.margin['right']
        plot_height = self.height - self.margin['top'] - self.margin['bottom']
        
        if not self.data or not self.categories:
            self._draw_empty_data_message()
            return
        
        # 简单树型图实现，仅展示一级节点
        node_height = 40
        node_width = 120
        spacing = 20
        
        # 计算子节点位置
        child_count = len(self.data)
        child_spacing = plot_width / (child_count + 1) if child_count > 0 else 0
        
        # 初始化动画参数
        self.tree_animation_progress = 0
        self.tree_animation_node_height = node_height
        self.tree_animation_node_width = node_width
        self.tree_animation_child_spacing = child_spacing
        self.tree_animation_data = self.data
        self.tree_animation_categories = self.categories
        self.tree_animation_center_x = self.width // 2
        self.tree_animation_root_y = self.margin['top'] + 50
        self.tree_animation_child_y = self.height - self.margin['bottom'] - 50
        
        # 开始动画
        self._update_tree_animation()
        
    def _update_tree_animation(self) -> None:
        """
        更新树型图动画
        """
        # 增加动画进度
        self.tree_animation_progress += 0.05
        if self.tree_animation_progress > 1:
            self.tree_animation_progress = 1
        
        # 清空之前的绘制内容
        self.canvas.delete('tree')
        
        node_height = self.tree_animation_node_height
        node_width = self.tree_animation_node_width
        child_spacing = self.tree_animation_child_spacing
        data = self.tree_animation_data
        categories = self.tree_animation_categories
        center_x = self.tree_animation_center_x
        root_y = self.tree_animation_root_y
        child_y = self.tree_animation_child_y
        
        # 绘制根节点（随动画进度放大）
        if self.tree_animation_progress > 0.1:
            root_scale = min(1, self.tree_animation_progress * 2)
            self.canvas.create_rectangle(
                center_x - node_width // 2 * root_scale, root_y - node_height // 2 * root_scale, 
                center_x + node_width // 2 * root_scale, root_y + node_height // 2 * root_scale,
                fill=self.colors[0], outline='', width=2,
                tags='tree'
            )
            self.canvas.create_text(
                center_x, root_y, 
                text='Root', 
                font=('SimHei', 12),
                fill='white',
                tags='tree'
            )
        
        # 计算子节点位置和绘制连接线（随动画进度显示）
        child_count = len(data)
        if child_count > 0 and self.tree_animation_progress > 0.4:
            visible_children = int(child_count * self.tree_animation_progress)
            if visible_children < 1:
                visible_children = 1
            
            for i in range(visible_children):
                child_x = self.margin['left'] + child_spacing * (i + 1)
                
                # 绘制连接线（随动画进度延长）
                if self.tree_animation_progress > 0.5:
                    # 计算线的当前终点
                    current_y = root_y + node_height // 2 + (child_y - node_height // 2 - root_y - node_height // 2) * (self.tree_animation_progress - 0.5) * 2
                    self.canvas.create_line(
                        center_x, root_y + node_height // 2, 
                        child_x, current_y,
                        width=2, fill='#999999',
                        tags='tree'
                    )
                
                # 绘制子节点（随动画进度放大）
                if self.tree_animation_progress > 0.7:
                    child_scale = min(1, (self.tree_animation_progress - 0.7) * 3.3)
                    self.canvas.create_rectangle(
                        child_x - node_width // 2 * child_scale, child_y - node_height // 2 * child_scale, 
                        child_x + node_width // 2 * child_scale, child_y + node_height // 2 * child_scale,
                        fill=self.colors[(i+1) % len(self.colors)], outline='', width=2,
                        tags='tree'
                    )
                    if i < len(categories):
                        self.canvas.create_text(
                            child_x, child_y - 5, 
                            text=categories[i], 
                            font=('SimHei', 10),
                            fill='white',
                            tags='tree'
                        )
                    self.canvas.create_text(
                        child_x, child_y + 5, 
                        text=str(data[i]), 
                        font=('SimHei', 10),
                        fill='white',
                        tags='tree'
                    )
        
        # 继续动画或结束
        if self.tree_animation_progress < 1:
            self.root.after(30, self._update_tree_animation)
    
    def _draw_sunburst_chart(self) -> None:
        """
        绘制旭日图（简化版）
        """
        # 直接调用带动画的版本
        self._draw_sunburst_chart_with_animation()
        
    def _draw_sunburst_chart_with_animation(self) -> None:
        """
        绘制带加载动画的旭日图
        """
        # 计算图表中心
        center_x = self.width // 2
        center_y = (self.height - self.margin['top']) // 2 + self.margin['top']
        
        # 检查数据
        if not self.data:
            self._draw_empty_data_message()
            return
        
        # 简单旭日图实现，仅展示一层圆环
        radius = min(center_x - self.margin['left'], center_y - self.margin['top'], 
                    self.width - center_x - self.margin['right'], self.height - center_y - self.margin['bottom']) * 0.8
        
        inner_radius = radius * 0.4  # 内圆半径
        
        # 计算总数据和每个数据的角度
        total = sum(self.data)
        if total == 0:
            self._draw_empty_data_message()
            return
        
        # 计算每个数据段的角度
        angles = []
        start_angle = 90  # 从正上方开始
        for value in self.data:
            angle = 360 * value / total
            end_angle = start_angle - angle
            angles.append((start_angle, angle))
            start_angle = end_angle
        
        # 初始化动画参数
        self.sunburst_animation_progress = 0
        self.sunburst_animation_center = (center_x, center_y)
        self.sunburst_animation_radius = radius
        self.sunburst_animation_inner_radius = inner_radius
        self.sunburst_animation_data = self.data
        self.sunburst_animation_categories = self.categories
        self.sunburst_animation_angles = angles
        
        # 开始动画
        self._update_sunburst_animation()
        
    def _update_sunburst_animation(self) -> None:
        """
        更新旭日图动画
        """
        # 增加动画进度
        self.sunburst_animation_progress += 0.05
        if self.sunburst_animation_progress > 1:
            self.sunburst_animation_progress = 1
        
        # 清空之前的绘制内容
        self.canvas.delete('sunburst')
        
        center_x, center_y = self.sunburst_animation_center
        radius = self.sunburst_animation_radius
        inner_radius = self.sunburst_animation_inner_radius
        data = self.sunburst_animation_data
        categories = self.sunburst_animation_categories
        angles = self.sunburst_animation_angles
        
        # 绘制中心圆（随动画进度放大）
        if self.sunburst_animation_progress > 0.1:
            center_scale = min(1, self.sunburst_animation_progress * 2)
            self.canvas.create_oval(
                center_x - inner_radius * center_scale, center_y - inner_radius * center_scale, 
                center_x + inner_radius * center_scale, center_y + inner_radius * center_scale,
                fill='#eeeeee', outline='', width=2,
                tags='sunburst'
            )
            self.canvas.create_text(
                center_x, center_y, 
                text='中心', 
                font=('SimHei', 14),
                fill='#333333',
                tags='sunburst'
            )
        
        # 绘制环形扇区（随动画进度显示）
        if self.sunburst_animation_progress > 0.3:
            # 计算当前进度对应的总角度
            total_angle_progress = self.sunburst_animation_progress - 0.3
            if total_angle_progress < 0:
                total_angle_progress = 0
            
            # 计算已经绘制的扇区数量
            visible_sectors = int(len(angles) * total_angle_progress * 3.3)
            if visible_sectors < 1:
                visible_sectors = 1
            
            # 绘制每个扇区
            current_start_angle = 90  # 从正上方开始
            for i in range(visible_sectors):
                if i < len(angles):
                    start_angle, angle = angles[i]
                    end_angle = start_angle - angle
                    
                    # 根据动画进度调整扇区的角度
                    progress_factor = min(1, (total_angle_progress - i/len(angles)*0.3) * 3.3)
                    current_angle = angle * progress_factor
                    current_end_angle = current_start_angle - current_angle
                    
                    # 使用Echarts配色
                    color = self.colors[i % len(self.colors)]
                    
                    # 绘制环形扇区
                    # 先绘制外圈
                    outer_arc = self.canvas.create_arc(
                        center_x - radius, center_y - radius, 
                        center_x + radius, center_y + radius,
                        start=current_start_angle, extent=current_angle, 
                        fill=color, outline='white', width=2,
                        tags='sunburst'
                    )
                    
                    # 再绘制内圈（覆盖部分外圈，形成环形）
                    inner_arc = self.canvas.create_arc(
                        center_x - inner_radius, center_y - inner_radius, 
                        center_x + inner_radius, center_y + inner_radius,
                        start=current_start_angle, extent=current_angle, 
                        fill='#eeeeee', outline='white', width=1,
                        tags='sunburst'
                    )
                    
                    # 绘制标签（仅在扇区接近完成时显示）
                    if progress_factor > 0.8 and categories and i < len(categories):
                        # 计算扇形中心角度，用于放置标签
                        mid_angle = math.radians((current_start_angle + current_end_angle) / 2)
                        label_radius = (radius + inner_radius) / 2  # 标签位置半径（环中间）
                        label_x = center_x + math.cos(mid_angle) * label_radius
                        label_y = center_y - math.sin(mid_angle) * label_radius
                        
                        # 确定文本方向
                        if 90 < mid_angle * 180 / math.pi < 270:
                            anchor = 'e'
                        else:
                            anchor = 'w'
                        
                        self.canvas.create_text(
                            label_x, label_y, 
                            text=categories[i], 
                            font=('SimHei', 10),
                            fill='white',
                            anchor=anchor,
                            tags='sunburst'
                        )
                    
                    # 更新起始角度
                    current_start_angle = current_end_angle
        
        # 继续动画或结束
        if self.sunburst_animation_progress < 1:
            self.root.after(30, self._update_sunburst_animation)
    
    def _draw_boxplot_chart(self) -> None:
        """
        绘制箱形图
        """
        # 直接调用带动画的版本
        self._draw_boxplot_chart_with_animation()
        
    def _draw_boxplot_chart_with_animation(self) -> None:
        """
        绘制带加载动画的箱形图
        """
        # 计算可用绘图区域
        plot_width = self.width - self.margin['left'] - self.margin['right']
        plot_height = self.height - self.margin['top'] - self.margin['bottom']
        
        if not self.data or len(self.data) < 5:
            self._draw_empty_data_message()
            return
        
        # 假设数据是多个箱形图的数据，每个箱形图包含[min, q1, median, q3, max]
        if all(isinstance(d, list) and len(d) >= 5 for d in self.data):
            box_data = self.data
        else:
            # 简单处理，将一维数据分成几组
            group_count = min(5, len(self.data) // 5)
            box_data = []
            for i in range(group_count):
                start_idx = i * len(self.data) // group_count
                end_idx = (i + 1) * len(self.data) // group_count
                group_data = sorted(self.data[start_idx:end_idx])
                if group_data:
                    # 计算基本统计量
                    min_val = group_data[0]
                    max_val = group_data[-1]
                    q1 = group_data[len(group_data) // 4]
                    median = group_data[len(group_data) // 2]
                    q3 = group_data[len(group_data) * 3 // 4]
                    box_data.append([min_val, q1, median, q3, max_val])
                else:
                    box_data.append([0, 0, 0, 0, 0])
        
        # 确定数据范围
        all_values = [val for box in box_data for val in box]
        min_value = min(all_values)
        max_value = max(all_values)
        if max_value == min_value:
            max_value = min_value + 1
        
        # 绘制坐标轴
        self.canvas.create_line(
            self.margin['left'], self.margin['top'], 
            self.margin['left'], self.height - self.margin['bottom'],
            width=2
        )
        self.canvas.create_line(
            self.margin['left'], self.height - self.margin['bottom'], 
            self.width - self.margin['right'], self.height - self.margin['bottom'],
            width=2
        )
        
        # 绘制Y轴刻度
        y_ticks = 5
        for i in range(y_ticks + 1):
            y = self.height - self.margin['bottom'] - (plot_height / y_ticks) * i
            self.canvas.create_line(
                self.margin['left'] - 5, y, 
                self.margin['left'], y,
                width=1
            )
            value = min_value + (max_value - min_value) * i / y_ticks
            self.canvas.create_text(
                self.margin['left'] - 10, y, 
                text=f'{value:.1f}', 
                font=('SimHei', 10),
                anchor='e'
            )
        
        # 计算箱形图参数
        box_width = plot_width / len(box_data) * 0.6
        box_space = plot_width / len(box_data) * 0.4
        
        # 计算所有Y坐标
        y_coords = []
        x_centers = []
        for i, box in enumerate(box_data):
            min_val, q1, median, q3, max_val = box
            
            # 计算Y坐标
            y_min = self.height - self.margin['bottom'] - (min_val - min_value) / (max_value - min_value) * plot_height
            y_q1 = self.height - self.margin['bottom'] - (q1 - min_value) / (max_value - min_value) * plot_height
            y_median = self.height - self.margin['bottom'] - (median - min_value) / (max_value - min_value) * plot_height
            y_q3 = self.height - self.margin['bottom'] - (q3 - min_value) / (max_value - min_value) * plot_height
            y_max = self.height - self.margin['bottom'] - (max_val - min_value) / (max_value - min_value) * plot_height
            
            # 计算X坐标
            x_center = self.margin['left'] + box_space / 2 + (box_width + box_space) * i + box_width / 2
            
            y_coords.append((y_min, y_q1, y_median, y_q3, y_max))
            x_centers.append(x_center)
        
        # 初始化动画参数
        self.boxplot_animation_progress = 0
        self.boxplot_animation_box_data = box_data
        self.boxplot_animation_box_width = box_width
        self.boxplot_animation_y_coords = y_coords
        self.boxplot_animation_x_centers = x_centers
        self.boxplot_animation_categories = self.categories
        
        # 开始动画
        self._update_boxplot_animation()
        
    def _update_boxplot_animation(self) -> None:
        """
        更新箱形图动画
        """
        # 增加动画进度
        self.boxplot_animation_progress += 0.05
        if self.boxplot_animation_progress > 1:
            self.boxplot_animation_progress = 1
        
        # 清空之前的绘制内容
        self.canvas.delete('boxplot')
        
        box_data = self.boxplot_animation_box_data
        box_width = self.boxplot_animation_box_width
        y_coords = self.boxplot_animation_y_coords
        x_centers = self.boxplot_animation_x_centers
        categories = self.boxplot_animation_categories
        
        # 计算当前可见的箱形图数量
        visible_boxes = int(len(box_data) * self.boxplot_animation_progress)
        if visible_boxes < 1:
            visible_boxes = 1
        
        # 绘制箱形图（随动画进度显示）
        for i in range(visible_boxes):
            if i < len(box_data):
                y_min, y_q1, y_median, y_q3, y_max = y_coords[i]
                x_center = x_centers[i]
                
                # 使用Echarts配色
                color = self.colors[i % len(self.colors)]
                
                # 根据动画进度计算当前显示的高度
                base_y = self.height - self.margin['bottom']
                
                # 绘制下须线（随动画进度延长）
                if self.boxplot_animation_progress > 0.3:
                    progress_factor = min(1, (self.boxplot_animation_progress - 0.3) * 1.4)
                    current_y_min = base_y - (base_y - y_min) * progress_factor
                    self.canvas.create_line(
                        x_center, current_y_min, 
                        x_center, y_q1,
                        width=1, fill='#333333',
                        tags='boxplot'
                    )
                
                # 绘制上须线（随动画进度延长）
                if self.boxplot_animation_progress > 0.5:
                    progress_factor = min(1, (self.boxplot_animation_progress - 0.5) * 2.5)
                    current_y_max = y_q3 - (y_q3 - y_max) * progress_factor
                    self.canvas.create_line(
                        x_center, y_q3, 
                        x_center, current_y_max,
                        width=1, fill='#333333',
                        tags='boxplot'
                    )
                
                # 绘制箱体（随动画进度显示）
                if self.boxplot_animation_progress > 0.7:
                    progress_factor = min(1, (self.boxplot_animation_progress - 0.7) * 3.3)
                    
                    # 箱体宽度随进度变化
                    current_width = box_width * progress_factor
                    
                    # 注意：Tkinter不支持CSS风格的透明度（如#5470c633），所以使用纯色填充
                    self.canvas.create_rectangle(
                        x_center - current_width / 2, y_q3, 
                        x_center + current_width / 2, y_q1,
                        fill=color, outline=color, width=2,
                        tags='boxplot'
                    )
                    
                    # 绘制中位数线
                    self.canvas.create_line(
                        x_center - current_width / 2, y_median, 
                        x_center + current_width / 2, y_median,
                        width=2, fill='#333333',
                        tags='boxplot'
                    )
                
                # 绘制X轴标签（随动画进度显示）
                if self.boxplot_animation_progress > 0.9 and categories and i < len(categories):
                    self.canvas.create_text(
                        x_center, self.height - self.margin['bottom'] + 20, 
                        text=categories[i], 
                        font=('SimHei', 10),
                        anchor='n',
                        angle=45,
                        tags='boxplot'
                    )
        
        # 继续动画或结束
        if self.boxplot_animation_progress < 1:
            self.root.after(30, self._update_boxplot_animation)
    
    def _draw_heatmap_chart(self) -> None:
        """
        绘制热力图（简化版）
        """
        # 直接调用带动画的版本
        self._draw_heatmap_chart_with_animation()
        
    def _draw_heatmap_chart_with_animation(self) -> None:
        """
        绘制带加载动画的热力图
        """
        # 计算可用绘图区域
        plot_width = self.width - self.margin['left'] - self.margin['right']
        plot_height = self.height - self.margin['top'] - self.margin['bottom']
        
        # 简单热力图实现，假设数据是二维的
        if not self.data:
            self._draw_empty_data_message()
            return
        
        # 确定数据维度
        if all(isinstance(d, list) for d in self.data):
            # 二维数据
            rows = len(self.data)
            cols = max(len(row) for row in self.data)
            data_2d = self.data
        else:
            # 一维数据转为简单的二维网格
            grid_size = max(1, int(math.sqrt(len(self.data))))
            rows = grid_size
            cols = grid_size
            data_2d = []
            for i in range(rows):
                row = self.data[i * cols : (i + 1) * cols]
                # 填充不足的数据
                while len(row) < cols:
                    row.append(0)
                data_2d.append(row)
        
        # 确定数据范围
        all_values = [val for row in data_2d for val in row]
        min_value = min(all_values)
        max_value = max(all_values)
        if max_value == min_value:
            max_value = min_value + 1
        
        # 计算每个格子的大小
        cell_width = plot_width / cols
        cell_height = plot_height / rows
        
        # 计算所有格子的颜色
        grid_colors = []
        grid_values = []
        for i in range(rows):
            row_colors = []
            row_values = []
            for j in range(cols):
                value = data_2d[i][j] if j < len(data_2d[i]) else 0
                row_values.append(value)
                
                # 计算颜色（从蓝色到红色的渐变）
                # 根据值的大小计算颜色强度
                intensity = (value - min_value) / (max_value - min_value)
                
                # 使用Echarts的颜色或者生成渐变色
                if intensity < 0.2:
                    color = '#5470c6'  # 蓝色
                elif intensity < 0.4:
                    color = '#91cc75'  # 绿色
                elif intensity < 0.6:
                    color = '#fac858'  # 黄色
                elif intensity < 0.8:
                    color = '#ee6666'  # 橙色
                else:
                    color = '#73c0de'  # 红色
                
                row_colors.append(color)
            grid_colors.append(row_colors)
            grid_values.append(row_values)
        
        # 初始化动画参数
        self.heatmap_animation_progress = 0
        self.heatmap_animation_rows = rows
        self.heatmap_animation_cols = cols
        self.heatmap_animation_cell_width = cell_width
        self.heatmap_animation_cell_height = cell_height
        self.heatmap_animation_grid_colors = grid_colors
        self.heatmap_animation_grid_values = grid_values
        self.heatmap_animation_min_value = min_value
        self.heatmap_animation_max_value = max_value
        self.heatmap_animation_categories = self.categories
        
        # 开始动画
        self._update_heatmap_animation()
        
    def _update_heatmap_animation(self) -> None:
        """
        更新热力图动画
        """
        # 增加动画进度
        self.heatmap_animation_progress += 0.05
        if self.heatmap_animation_progress > 1:
            self.heatmap_animation_progress = 1
        
        # 清空之前的绘制内容
        self.canvas.delete('heatmap')
        
        rows = self.heatmap_animation_rows
        cols = self.heatmap_animation_cols
        cell_width = self.heatmap_animation_cell_width
        cell_height = self.heatmap_animation_cell_height
        grid_colors = self.heatmap_animation_grid_colors
        grid_values = self.heatmap_animation_grid_values
        min_value = self.heatmap_animation_min_value
        max_value = self.heatmap_animation_max_value
        categories = self.heatmap_animation_categories
        
        # 计算当前可见的格子数量（按对角线方向填充）
        total_cells = rows * cols
        visible_cells = int(total_cells * self.heatmap_animation_progress)
        if visible_cells < 1:
            visible_cells = 1
        
        # 按对角线顺序确定可见的格子
        visible_indices = []
        for i in range(rows):
            for j in range(cols):
                # 计算格子的对角线距离（从左上角开始）
                diag_dist = i + j
                visible_indices.append((i, j, diag_dist))
        
        # 按对角线距离排序
        visible_indices.sort(key=lambda x: x[2])
        
        # 只保留可见的格子
        visible_indices = visible_indices[:visible_cells]
        
        # 绘制热力图格子
        for i, j, _ in visible_indices:
            if i < rows and j < cols:
                color = grid_colors[i][j]
                value = grid_values[i][j]
                intensity = (value - min_value) / (max_value - min_value) if max_value > min_value else 0
                
                # 计算格子位置
                x1 = self.margin['left'] + j * cell_width
                y1 = self.margin['top'] + i * cell_height
                x2 = x1 + cell_width
                y2 = y1 + cell_height
                
                # 根据动画进度计算当前显示的格子大小和透明度
                size_factor = min(1, self.heatmap_animation_progress * 1.2)
                current_width = cell_width * size_factor
                current_height = cell_height * size_factor
                current_x1 = x1 + (cell_width - current_width) / 2
                current_y1 = y1 + (cell_height - current_height) / 2
                current_x2 = current_x1 + current_width
                current_y2 = current_y1 + current_height
                
                # 绘制格子
                self.canvas.create_rectangle(
                    current_x1, current_y1, 
                    current_x2, current_y2,
                    fill=color, outline='white', width=1,
                    tags='heatmap'
                )
                
                # 在格子中心显示数值（随动画进度显示）
                if self.heatmap_animation_progress > 0.7:
                    self.canvas.create_text(
                        (x1 + x2) / 2, (y1 + y2) / 2, 
                        text=f'{value}', 
                        font=('SimHei', 10),
                        fill='white' if intensity > 0.5 else '#333333',
                        tags='heatmap'
                    )
        
        # 绘制X轴和Y轴标签（随动画进度显示）
        if categories and self.heatmap_animation_progress > 0.9:
            # X轴标签
            for j in range(min(cols, len(categories))):
                x = self.margin['left'] + j * cell_width + cell_width / 2
                self.canvas.create_text(
                    x, self.height - self.margin['bottom'] + 20, 
                    text=categories[j], 
                    font=('SimHei', 10),
                    anchor='n',
                    angle=45,
                    tags='heatmap'
                )
            
            # Y轴标签（使用数据的前几行作为标签）
            for i in range(min(rows, len(categories))):
                y = self.margin['top'] + i * cell_height + cell_height / 2
                self.canvas.create_text(
                    self.margin['left'] - 10, y, 
                    text=categories[i], 
                    font=('SimHei', 10),
                    anchor='e',
                    tags='heatmap'
                )
        
        # 继续动画或结束
        if self.heatmap_animation_progress < 1:
            self.root.after(30, self._update_heatmap_animation)
    
    def _draw_map_chart(self) -> None:
        """
        绘制地图（简化版）
        """
        # 直接调用带动画的版本
        self._draw_map_chart_with_animation()
        
    def _draw_map_chart_with_animation(self) -> None:
        """
        绘制带加载动画的地图
        """
        # 计算可用绘图区域
        plot_width = self.width - self.margin['left'] - self.margin['right']
        plot_height = self.height - self.margin['top'] - self.margin['bottom']
        
        # 简化的地图实现，仅显示一些示例区域
        self.canvas.create_text(
            self.width // 2, self.height // 2, 
            text='地图功能需要更复杂的地理数据支持', 
            font=('SimHei', 14),
            fill='#999999'
        )
        
        # 绘制一些示例矩形区域表示地图上的区域
        regions = [
            (self.margin['left'] + 50, self.margin['top'] + 50, 100, 100, '区域1'),
            (self.margin['left'] + 200, self.margin['top'] + 80, 120, 80, '区域2'),
            (self.margin['left'] + 350, self.margin['top'] + 40, 90, 110, '区域3'),
            (self.margin['left'] + 100, self.margin['top'] + 200, 80, 90, '区域4'),
            (self.margin['left'] + 250, self.margin['top'] + 220, 100, 70, '区域5'),
        ]
        
        # 初始化动画参数
        self.map_animation_progress = 0
        self.map_animation_regions = regions
        
        # 开始动画
        self._update_map_animation()
        
    def _update_map_animation(self) -> None:
        """
        更新地图动画
        """
        # 增加动画进度
        self.map_animation_progress += 0.05
        if self.map_animation_progress > 1:
            self.map_animation_progress = 1
        
        # 清空之前的绘制内容
        self.canvas.delete('map')
        
        regions = self.map_animation_regions
        
        # 计算当前可见的区域数量
        visible_regions = int(len(regions) * self.map_animation_progress)
        if visible_regions < 1:
            visible_regions = 1
        
        # 绘制区域（随动画进度显示）
        for i in range(visible_regions):
            if i < len(regions):
                x, y, width, height, name = regions[i]
                
                # 使用Echarts配色
                color = self.colors[i % len(self.colors)]
                
                # 根据动画进度计算当前显示的区域大小
                size_factor = min(1, self.map_animation_progress * 1.5)
                current_width = width * size_factor
                current_height = height * size_factor
                current_x = x + (width - current_width) / 2
                current_y = y + (height - current_height) / 2
                
                # 绘制区域
                self.canvas.create_rectangle(
                    current_x, current_y, 
                    current_x + current_width, current_y + current_height,
                    fill=color, outline='white', width=2,
                    tags='map'
                )
                
                # 绘制区域名称（随动画进度显示）
                if self.map_animation_progress > 0.7:
                    self.canvas.create_text(
                        x + width // 2, y + height // 2, 
                        text=name, 
                        font=('SimHei', 12),
                        fill='white',
                        tags='map'
                    )
        
        # 继续动画或结束
        if self.map_animation_progress < 1:
            self.root.after(30, self._update_map_animation)
    
    def _draw_sankey_chart(self) -> None:
        """
        绘制桑基图（简化版）
        """
        # 直接调用带动画的版本
        self._draw_sankey_chart_with_animation()
        
    def _draw_sankey_chart_with_animation(self) -> None:
        """
        绘制带加载动画的桑基图
        """
        # 桑基图需要更复杂的数据结构（节点和连接）
        self.canvas.create_text(
            self.width // 2, self.height // 2, 
            text='桑基图功能需要节点和连接数据支持', 
            font=('SimHei', 14),
            fill='#999999'
        )
        
        # 绘制一些简单的示例
        nodes = [
            (self.margin['left'] + 50, self.margin['top'] + 100, 20, 50, 'A'),
            (self.margin['left'] + 50, self.margin['top'] + 200, 20, 50, 'B'),
            (self.width - self.margin['right'] - 20, self.margin['top'] + 80, 20, 40, 'C'),
            (self.width - self.margin['right'] - 20, self.margin['top'] + 160, 20, 60, 'D'),
            (self.width - self.margin['right'] - 20, self.margin['top'] + 260, 20, 40, 'E'),
        ]
        
        links = [
            (0, 2, 30),  # A -> C
            (0, 3, 20),  # A -> D
            (1, 3, 25),  # B -> D
            (1, 4, 25),  # B -> E
        ]
        
        # 初始化动画参数
        self.sankey_animation_progress = 0
        self.sankey_animation_nodes = nodes
        self.sankey_animation_links = links
        
        # 开始动画
        self._update_sankey_animation()
        
    def _update_sankey_animation(self) -> None:
        """
        更新桑基图动画
        """
        # 增加动画进度
        self.sankey_animation_progress += 0.05
        if self.sankey_animation_progress > 1:
            self.sankey_animation_progress = 1
        
        # 清空之前的绘制内容
        self.canvas.delete('sankey')
        
        nodes = self.sankey_animation_nodes
        links = self.sankey_animation_links
        
        # 绘制节点（随动画进度显示）
        if self.sankey_animation_progress > 0.2:
            # 计算节点的显示进度
            node_progress = min(1, (self.sankey_animation_progress - 0.2) / 0.3)
            
            # 当前可见的节点数量
            visible_nodes = int(len(nodes) * node_progress)
            if visible_nodes < 1:
                visible_nodes = 1
            
            for i in range(visible_nodes):
                if i < len(nodes):
                    x, y, width, height, name = nodes[i]
                    
                    # 根据动画进度计算当前显示的节点大小
                    size_factor = min(1, node_progress * 1.5)
                    current_width = width * size_factor
                    current_height = height * size_factor
                    current_x = x + (width - current_width) / 2
                    current_y = y + (height - current_height) / 2
                    
                    # 绘制节点
                    self.canvas.create_rectangle(
                        current_x, current_y, 
                        current_x + current_width, current_y + current_height,
                        fill=self.colors[i % len(self.colors)], outline='white', width=2,
                        tags='sankey'
                    )
                    
                    # 绘制节点名称（随动画进度显示）
                    if self.sankey_animation_progress > 0.5:
                        self.canvas.create_text(
                            x - 10, y + height // 2, 
                            text=name, 
                            font=('SimHei', 12),
                            fill='#333333',
                            anchor='e',
                            tags='sankey'
                        )
        
        # 绘制连接（随动画进度显示）
        if self.sankey_animation_progress > 0.6:
            # 计算连接的显示进度
            link_progress = min(1, (self.sankey_animation_progress - 0.6) / 0.4)
            
            # 当前可见的连接数量
            visible_links = int(len(links) * link_progress)
            if visible_links < 1:
                visible_links = 1
            
            for i in range(visible_links):
                if i < len(links):
                    source, target, value = links[i]
                    if source < len(nodes) and target < len(nodes):
                        x1, y1, w1, h1, _ = nodes[source]
                        x2, y2, w2, h2, _ = nodes[target]
                        
                        # 计算连接的起点和终点
                        start_x = x1 + w1
                        start_y = y1 + h1 / 2
                        end_x = x2
                        end_y = y2 + h2 / 2
                        
                        # 根据流量设置线宽
                        line_width = max(1, min(10, value / 10))
                        
                        # 根据动画进度计算连接线的长度
                        current_end_x = start_x + (end_x - start_x) * link_progress
                        current_end_y = start_y + (end_y - start_y) * link_progress
                        
                        # 绘制连接线
                        self.canvas.create_line(
                            start_x, start_y, 
                            current_end_x, current_end_y,
                            width=line_width, fill=self.colors[i % len(self.colors)],
                            tags='sankey'
                        )
        
        # 继续动画或结束
        if self.sankey_animation_progress < 1:
            self.root.after(30, self._update_sankey_animation)
    
    def _draw_funnel_chart(self) -> None:
        """
        绘制漏斗图
        """
        # 直接调用带动画的版本
        self._draw_funnel_chart_with_animation()
        
    def _draw_funnel_chart_with_animation(self) -> None:
        """
        绘制带加载动画的漏斗图
        """
        # 计算可用绘图区域
        plot_width = self.width - self.margin['left'] - self.margin['right']
        plot_height = self.height - self.margin['top'] - self.margin['bottom']
        
        if not self.data:
            self._draw_empty_data_message()
            return
        
        # 确定数据范围
        max_value = max(self.data)
        if max_value == 0:
            max_value = 1
        
        # 计算漏斗图的基本参数
        funnel_height = plot_height * 0.8
        max_width = plot_width * 0.8
        min_width = max_width * 0.3
        step_height = funnel_height / len(self.data)
        
        # 预先计算所有层的宽度和位置
        funnel_layers = []
        for i, value in enumerate(self.data):
            # 计算当前层的宽度
            width_ratio = value / max_value
            current_width = min_width + (max_width - min_width) * width_ratio
            
            # 计算当前层的位置
            x1 = self.width // 2 - current_width / 2
            y1 = self.margin['top'] + i * step_height
            x2 = self.width // 2 + current_width / 2
            y2 = y1 + step_height
            
            # 使用Echarts配色
            color = self.colors[i % len(self.colors)]
            
            funnel_layers.append((x1, y1, x2, y2, color, value))
        
        # 初始化动画参数
        self.funnel_animation_progress = 0
        self.funnel_animation_layers = funnel_layers
        self.funnel_animation_categories = self.categories
        
        # 开始动画
        self._update_funnel_animation()
        
    def _update_funnel_animation(self) -> None:
        """
        更新漏斗图动画
        """
        # 增加动画进度
        self.funnel_animation_progress += 0.05
        if self.funnel_animation_progress > 1:
            self.funnel_animation_progress = 1
        
        # 清空之前的绘制内容
        self.canvas.delete('funnel')
        
        layers = self.funnel_animation_layers
        categories = self.funnel_animation_categories
        
        # 计算当前可见的层数
        visible_layers = int(len(layers) * self.funnel_animation_progress)
        if visible_layers < 1:
            visible_layers = 1
        
        # 绘制漏斗图（随动画进度显示）
        for i in range(visible_layers):
            if i < len(layers):
                x1, y1, x2, y2, color, value = layers[i]
                
                # 根据动画进度计算当前显示的层高度
                height_factor = min(1, self.funnel_animation_progress * 1.5)
                layer_height = y2 - y1
                current_height = layer_height * height_factor
                current_y2 = y1 + current_height
                
                # 绘制漏斗层
                self.canvas.create_rectangle(
                    x1, y1, 
                    x2, current_y2,
                    fill=color, outline='white', width=2,
                    tags='funnel'
                )
                
                # 绘制标签（随动画进度显示）
                if self.funnel_animation_progress > 0.7 and categories and i < len(categories):
                    # 在左侧显示类别名称
                    self.canvas.create_text(
                        x1 - 10, (y1 + y2) / 2, 
                        text=categories[i], 
                        font=('SimHei', 12),
                        fill='#333333',
                        anchor='e',
                        tags='funnel'
                    )
                    
                    # 在右侧显示数值
                    self.canvas.create_text(
                        x2 + 10, (y1 + y2) / 2, 
                        text=str(value), 
                        font=('SimHei', 12),
                        fill='#333333',
                        anchor='w',
                        tags='funnel'
                    )
        
        # 继续动画或结束
        if self.funnel_animation_progress < 1:
            self.root.after(30, self._update_funnel_animation)
    
    def _draw_gauge_chart(self) -> None:
        """
        绘制仪表盘（美化版）
        """
        # 直接调用带动画的版本
        self._draw_gauge_chart_with_animation()
        
    def _draw_gauge_chart_with_animation(self) -> None:
        """
        绘制带加载动画的仪表盘
        """
        # 计算图表中心和半径
        center_x = self.width // 2
        center_y = (self.height - self.margin['top']) // 2 + self.margin['top']
        radius = min(center_x - self.margin['left'], center_y - self.margin['top'], 
                    self.width - center_x - self.margin['right'], self.height - center_y - self.margin['bottom']) * 0.8
        
        if not self.data:
            self._draw_empty_data_message()
            return
        
        # 使用第一个数据点作为仪表盘的值
        value = self.data[0]
        
        # 初始化动画参数
        self.gauge_animation_progress = 0
        self.gauge_target_value = value
        self.gauge_animation_center = (center_x, center_y)
        self.gauge_animation_radius = radius
        self.gauge_animation_min_value = 0
        self.gauge_animation_max_value = 100
        
        # 开始动画
        self._update_gauge_animation()
        
    def _update_gauge_animation(self) -> None:
        """
        更新仪表盘动画
        """
        # 增加动画进度
        self.gauge_animation_progress += 0.05
        if self.gauge_animation_progress > 1:
            self.gauge_animation_progress = 1
        
        # 清空之前的绘制内容（保留标题等其他元素）
        self.canvas.delete('gauge')
        
        center_x, center_y = self.gauge_animation_center
        radius = self.gauge_animation_radius
        min_value = self.gauge_animation_min_value
        max_value = self.gauge_animation_max_value
        
        # 计算当前显示的值
        current_value = self.gauge_animation_progress * self.gauge_target_value
        
        # 绘制仪表盘背景圆环（带动画）
        if self.gauge_animation_progress > 0.1:
            bg_progress = min(1, (self.gauge_animation_progress - 0.1) / 0.2)
            self.canvas.create_arc(
                center_x - radius * bg_progress, center_y - radius * bg_progress, 
                center_x + radius * bg_progress, center_y + radius * bg_progress,
                start=180, extent=180, 
                fill='#f0f0f0', outline='', width=0,
                tags='gauge'
            )
        
        # 绘制渐变颜色区域（从绿色到红色）（带动画）
        if self.gauge_animation_progress > 0.3:
            color_progress = min(1, (self.gauge_animation_progress - 0.3) / 0.2)
            # 绘制绿色区域（0-60%）
            self.canvas.create_arc(
                center_x - radius * 0.95 * color_progress, center_y - radius * 0.95 * color_progress, 
                center_x + radius * 0.95 * color_progress, center_y + radius * 0.95 * color_progress,
                start=180, extent=108,  # 60% of 180 degrees
                fill='#91cc75', outline='', width=0,
                tags='gauge'
            )
            # 绘制黄色区域（60-80%）
            self.canvas.create_arc(
                center_x - radius * 0.95 * color_progress, center_y - radius * 0.95 * color_progress, 
                center_x + radius * 0.95 * color_progress, center_y + radius * 0.95 * color_progress,
                start=288, extent=36,  # 20% of 180 degrees
                fill='#fac858', outline='', width=0,
                tags='gauge'
            )
            # 绘制红色区域（80-100%）
            self.canvas.create_arc(
                center_x - radius * 0.95 * color_progress, center_y - radius * 0.95 * color_progress, 
                center_x + radius * 0.95 * color_progress, center_y + radius * 0.95 * color_progress,
                start=324, extent=36,  # 20% of 180 degrees
                fill='#ee6666', outline='', width=0,
                tags='gauge'
            )
        
        # 绘制内部白色背景，形成环形效果（带动画）
        if self.gauge_animation_progress > 0.35:
            inner_progress = min(1, (self.gauge_animation_progress - 0.35) / 0.15)
            self.canvas.create_oval(
                center_x - radius * 0.7 * inner_progress, center_y - radius * 0.7 * inner_progress, 
                center_x + radius * 0.7 * inner_progress, center_y + radius * 0.7 * inner_progress,
                fill='white', outline='', width=0,
                tags='gauge'
            )
        
        # 绘制主刻度和标签（带动画）
        if self.gauge_animation_progress > 0.5:
            tick_progress = min(1, (self.gauge_animation_progress - 0.5) / 0.15)
            main_tick_count = 10
            max_tick = int((main_tick_count + 1) * tick_progress)
            
            for i in range(max_tick):
                angle = 180 + i * 180 / main_tick_count  # 从左侧开始，到右侧结束
                radians = math.radians(angle)
                
                # 内刻度位置
                inner_radius = radius * 0.75
                inner_x = center_x + inner_radius * math.cos(radians)
                inner_y = center_y + inner_radius * math.sin(radians)
                
                # 外刻度位置
                outer_radius = radius * 0.95
                outer_x = center_x + outer_radius * math.cos(radians)
                outer_y = center_y + outer_radius * math.sin(radians)
                
                # 绘制刻度线
                line_width = 3 if i % 2 == 0 else 2  # 每两个刻度加粗显示
                self.canvas.create_line(
                    inner_x, inner_y, 
                    outer_x, outer_y,
                    width=line_width, fill='#333333',
                    tags='gauge'
                )
                
                # 绘制刻度标签（每隔一个刻度显示）
                if i % 2 == 0:
                    label_radius = radius * 1.15
                    label_x = center_x + label_radius * math.cos(radians)
                    label_y = center_y + label_radius * math.sin(radians)
                    label_value = min_value + (max_value - min_value) * i / main_tick_count
                    self.canvas.create_text(
                        label_x, label_y, 
                        text=f'{int(label_value)}', 
                        font=('SimHei', 12, 'bold'),
                        fill='#333333',
                        tags='gauge'
                    )
        
        # 绘制次刻度（带动画）
        if self.gauge_animation_progress > 0.6:
            sub_tick_progress = min(1, (self.gauge_animation_progress - 0.6) / 0.1)
            sub_tick_count = 40
            max_sub_tick = int((sub_tick_count + 1) * sub_tick_progress)
            
            for i in range(max_sub_tick):
                # 跳过主刻度的位置
                if i % 4 == 0:
                    continue
                    
                angle = 180 + i * 180 / sub_tick_count
                radians = math.radians(angle)
                
                # 内刻度位置
                inner_radius = radius * 0.85
                inner_x = center_x + inner_radius * math.cos(radians)
                inner_y = center_y + inner_radius * math.sin(radians)
                
                # 外刻度位置
                outer_radius = radius * 0.95
                outer_x = center_x + outer_radius * math.cos(radians)
                outer_y = center_y + outer_radius * math.sin(radians)
                
                # 绘制次刻度线
                self.canvas.create_line(
                    inner_x, inner_y, 
                    outer_x, outer_y,
                    width=1, fill='#666666',
                    tags='gauge'
                )
        
        # 绘制指针和中心圆（带动画）
        if self.gauge_animation_progress > 0.65:
            # 计算指针角度
            value_ratio = min(1, max(0, (current_value - min_value) / (max_value - min_value)))
            pointer_angle = 180 + value_ratio * 180  # 角度范围：180°-360°（对应0-100）
            pointer_radians = math.radians(pointer_angle)
            
            # 绘制指针
            pointer_length = radius * 0.7
            pointer_x = center_x + pointer_length * math.cos(pointer_radians)
            pointer_y = center_y + pointer_length * math.sin(pointer_radians)
            
            # 绘制指针的三角形箭头
            arrow_size = 10
            arrow_angle1 = math.radians(pointer_angle - 15)
            arrow_angle2 = math.radians(pointer_angle + 15)
            arrow_x1 = center_x + (pointer_length - arrow_size) * math.cos(arrow_angle1)
            arrow_y1 = center_y + (pointer_length - arrow_size) * math.sin(arrow_angle1)
            arrow_x2 = center_x + (pointer_length - arrow_size) * math.cos(arrow_angle2)
            arrow_y2 = center_y + (pointer_length - arrow_size) * math.sin(arrow_angle2)
            
            # 绘制指针的主线
            self.canvas.create_line(
                center_x, center_y, 
                pointer_x, pointer_y,
                width=3, fill='#ee6666',
                tags='gauge'
            )
            
            # 绘制指针的箭头
            self.canvas.create_polygon(
                pointer_x, pointer_y,
                arrow_x1, arrow_y1,
                arrow_x2, arrow_y2,
                fill='#ee6666', outline='',
                tags='gauge'
            )
            
            # 绘制中心圆（带有阴影效果）
            self.canvas.create_oval(
                center_x - 12, center_y - 12, 
                center_x + 12, center_y + 12,
                fill='#dddddd', outline='', width=0,
                tags='gauge'
            )
            self.canvas.create_oval(
                center_x - 10, center_y - 10, 
                center_x + 10, center_y + 10,
                fill='#ee6666', outline='', width=0,
                tags='gauge'
            )
        
        # 绘制当前值（带动画）
        if self.gauge_animation_progress > 0.8:
            value_progress = min(1, (self.gauge_animation_progress - 0.8) / 0.2)
            value_bg_radius = radius * 0.3 * value_progress
            
            # 绘制值背景
            self.canvas.create_oval(
                center_x - value_bg_radius, center_y - value_bg_radius * 0.5, 
                center_x + value_bg_radius, center_y + value_bg_radius * 0.5,
                fill='white', outline='#dddddd', width=1,
                tags='gauge'
            )
            
            # 绘制当前值
            self.canvas.create_text(
                center_x, center_y, 
                text=f'{int(current_value)}', 
                font=('SimHei', 28, 'bold'),
                fill='#333333',
                tags='gauge'
            )
            
            # 绘制百分比符号
            self.canvas.create_text(
                center_x + value_bg_radius * 0.7, center_y, 
                text='%', 
                font=('SimHei', 14, 'bold'),
                fill='#666666',
                tags='gauge'
            )
        
        # 绘制标题（如果有）（带动画）
        if self.categories and len(self.categories) > 0 and self.gauge_animation_progress > 0.85:
            title_progress = min(1, (self.gauge_animation_progress - 0.85) / 0.15)
            # 标题透明度随进度变化
            fill_color = f'#333333{int(title_progress * 255):02x}'  # RGBA格式，但tkinter不直接支持，这里使用纯黑色
            self.canvas.create_text(
                center_x, center_y + radius * 0.5, 
                text=self.categories[0], 
                font=('SimHei', 16, 'bold'),
                fill='#333333',
                tags='gauge'
            )
        
        # 继续动画或结束
        if self.gauge_animation_progress < 1:
            self.root.after(30, self._update_gauge_animation)
    
    def enable_dynamic_update(self, interval: int = 1000) -> None:
        """
        启用图表动态更新功能
        
        参数:
            interval: int - 更新间隔（毫秒），默认为1000毫秒
        """
        self.is_dynamic = True
        self._update_interval = interval
        self._dynamic_update()
    
    def disable_dynamic_update(self) -> None:
        """
        禁用图表动态更新功能
        """
        self.is_dynamic = False
    
    def _dynamic_update(self) -> None:
        """
        动态更新图表数据（示例实现）
        """
        if self.is_dynamic:
            # 生成新的随机数据（实际应用中应该从数据源获取）
            new_data = []
            for value in self.data:
                # 在原值基础上添加一些随机波动
                # 确保value是数字类型
                try:
                    num_value = float(value)
                    change = random.uniform(-0.1, 0.1) * num_value
                    new_value = max(0, num_value + change)  # 确保值不为负数
                except (ValueError, TypeError):
                    # 如果无法转换为数字，则保持原值
                    new_value = value
                new_data.append(new_value)
            
            # 更新图表数据
            self.set_data(new_data, self.categories)
            
            # 调度下一次更新
            self.root.after(self._update_interval, self._dynamic_update)
    
    def start(self) -> None:
        """
        启动图表应用的主循环
        """
        self.root.mainloop()

# 示例用法
if __name__ == '__main__':
    # 创建一个简单的示例应用
    def create_sample_app():
        """\创建示例应用"""
        root = tk.Tk()
        root.title('WitTkChart 示例')
        root.geometry('900x700')
        
        # 创建框架
        control_frame = ttk.Frame(root, padding=10)
        control_frame.pack(side=tk.TOP, fill=tk.X)
        
        chart_frame = ttk.Frame(root, padding=10)
        chart_frame.pack(side=tk.TOP, fill=tk.BOTH, expand=True)
        
        # 创建图表类型选择下拉框
        chart_type_label = ttk.Label(control_frame, text='图表类型:')
        chart_type_label.pack(side=tk.LEFT, padx=5)
        
        chart_type_var = tk.StringVar(value='bar')
        chart_type_combo = ttk.Combobox(
            control_frame, 
            textvariable=chart_type_var, 
            values=['bar', 'line', 'pie', 'scatter', 'radar', 'tree', 'sunburst', 'boxplot', 'heatmap', 'map', 'sankey', 'funnel', 'gauge'],
            width=10
        )
        chart_type_combo.pack(side=tk.LEFT, padx=5)
        
        # 创建动态更新复选框
        dynamic_var = tk.BooleanVar(value=False)
        dynamic_check = ttk.Checkbutton(control_frame, text='动态更新', variable=dynamic_var)
        dynamic_check.pack(side=tk.LEFT, padx=10)
        
        # 创建更新按钮
        update_button = ttk.Button(control_frame, text='更新图表')
        update_button.pack(side=tk.LEFT, padx=5)
        
        # 创建图表数据
        data = [65, 59, 80, 81, 56, 55, 72]
        categories = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
        
        # 创建图表对象
        chart = WitTkChart(
            root=chart_frame, 
            chart_type='bar', 
            data=data, 
            categories=categories,
            title='一周销售额统计'
        )
        
        # 定义更新函数
        def update_chart():
            """更新图表"""
            chart.set_chart_type(chart_type_var.get())
            
            # 根据图表类型生成不同的数据
            new_chart_type = chart_type_var.get()
            if new_chart_type == 'scatter':
                # 生成二维散点数据
                new_data = [(random.randint(10, 90), random.randint(10, 90)) for _ in range(50)]
                chart.set_data(new_data)
            elif new_chart_type == 'radar':
                # 生成雷达图数据
                new_data = [65, 59, 80, 81, 56, 55, 40]
                new_categories = ['语文', '数学', '英语', '物理', '化学', '生物', '历史']
                chart.set_data(new_data, new_categories)
            elif new_chart_type == 'gauge':
                # 生成仪表盘数据
                new_data = [random.randint(0, 100)]
                new_categories = ['完成度']
                chart.set_data(new_data, new_categories)
            else:
                # 其他图表类型使用相同的数据结构
                chart.set_data([random.randint(30, 100) for _ in range(7)], categories)
            
            # 启用或禁用动态更新
            if dynamic_var.get():
                chart.enable_dynamic_update(1000)
            else:
                chart.disable_dynamic_update()
        
        # 绑定事件
        update_button.config(command=update_chart)
        chart_type_combo.bind('<<ComboboxSelected>>', lambda event: update_chart())
        
        return root
    
    # 启动示例应用
    app = create_sample_app()
    app.mainloop()